﻿using Microsoft.EntityFrameworkCore;
using NetCoreBBS.Entities;
using NetCoreBBS.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace NetCoreBBS.Infrastructure.Repositorys
{
    public class Repository<T> : IRepository<T> where T : BaseEntity
    {
        private readonly DataContext _dbContext;
        private DbSet<T> _entities;

        public Repository(DataContext dbContext)
        {
            _dbContext = dbContext;
        }

        public virtual T GetById(int id)
        {
            return _dbContext.Set<T>().Find(id);
        }

        public virtual IEnumerable<T> List()
        {
            return _dbContext.Set<T>().AsEnumerable();
        }

        public virtual IEnumerable<T> List(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
        {
            return _dbContext.Set<T>()
                   .Where(predicate)
                   .AsEnumerable();
        }

        public T Add(T entity)
        {
            var res = _dbContext.Set<T>().Add(entity);
            _dbContext.SaveChanges();
            return res.Entity;
        }

        public void Edit(T entity)
        {
            _dbContext.Entry(entity).State = EntityState.Modified;
            _dbContext.SaveChanges();
        }

        /// <summary>
        /// Delete entity
        /// </summary>
        /// <param name="entity">Entity</param>
        public virtual int Delete(Expression<Func<T, bool>> predicate)
        {
            try
            {
                var entitys = this.Entities.Where(predicate);
                foreach (var item in entitys)
                    this.Entities.Remove(item);

                return _dbContext.SaveChanges();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return 0;
            }
        }

        public virtual async Task<int> DeleteAsync(Expression<Func<T, bool>> predicate)
        {
            try
            {
                var entitys = this.Entities.Where(predicate);
                foreach (var item in entitys)
                    this.Entities.Remove(item);

                return await _dbContext.SaveChangesAsync();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return 0;
            }
        }

        public bool Exist(Expression<Func<T, bool>> anyLambda)
        {
            return Entities.Any(anyLambda);
        }

        public int Count(Expression<Func<T, bool>> predicate)
        {
            if (predicate == null)
                return Entities.Count();

            return Entities.Count(predicate);
        }

        #region Properties

        /// <summary>
        /// Gets a table
        /// </summary>
        public virtual IQueryable<T> Table
        {
            get
            {
                return this.Entities;
            }
        }

        /// <summary>
        /// Gets a table with "no tracking" enabled (EF feature) Use it only when you load record(s) only for read-only operations
        /// </summary>
        public virtual IQueryable<T> TableNoTracking
        {
            get
            {
                return this.Entities.AsNoTracking();
            }
        }

        /// <summary>
        /// Entities
        /// </summary>
        protected virtual DbSet<T> Entities
        {
            get
            {
                if (_entities == null)
                    _entities = _dbContext.Set<T>();
                return _entities;
            }
        }

        #endregion
    }
}
